package com.hex.ds.hdtp.core.inf.data.contrast.service.impl;

import com.hex.bigdata.hbda.utils.StringUtils;
import com.hex.ds.hdtp.core.inf.metadata.entity.TableFieldsEntity;
import com.hex.ds.hdtp.core.inf.metadata.repository.ISourceConfInfoRepository;
import com.hex.ds.hdtp.core.inf.metadata.service.impl.ImpalaMethodService;
import com.hex.ds.hdtp.core.inf.metadata.service.impl.SourceMethodHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Package com.hex.ds.hdtp.core.inf.compare.dataInfo.service.impl
 * @ClassName ImpalaInfoService
 * @Description Impala数据库操作
 * @Author Wang zhihao
 * @Date 2023/8/6 22:05
 * @Version v1.0
 **/
@Slf4j
@Service("COMPARE_IMPALA")
public class ImpalaInfoService extends AbstractDataInfoService {

    private final ImpalaMethodService impalaMethodService;

    public static final String COLUMN_NAME = "column_name";

    public ImpalaInfoService(ISourceConfInfoRepository sourceConfInfoRepository, SourceMethodHandlerContext sourceMethodHandlerContext, ImpalaMethodService impalaMethodService) {
        super(sourceConfInfoRepository, sourceMethodHandlerContext);
        this.impalaMethodService = impalaMethodService;
    }


    /**
     * @param sourceCode
     * @param schema
     * @param table
     * @Method selectPartitionField
     * @Param
     * @Return List<String>
     * @Description 分区字段
     * @Author Wang zhihao
     * @Date 2023/8/17 19:51
     * @Version V1.0
     */
    @Override
    public List<String> selectPartitionField(String sourceCode, String schema, String table) throws SQLException {
        return impalaMethodService.getPartitionColumns(schema, table, sourceCode);
    }


    /**
     * @param tableFieldsEntities
     * @param partitionFieldName  分区字段名
     * @param isCover             是否覆盖建表
     * @Method buildCreateTableSql
     * @Param
     * @Return java.lang.String
     * @Description 建立建表语句
     * @Author Wang zhihao
     * @Date 2023/8/18 14:47
     * @Version V1.3
     */
    @Override
    public String buildCreateTableSql(List<TableFieldsEntity> tableFieldsEntities, List<String> partitionFieldName, String isCover) {
        // 是否覆盖建表
        String isDropSql = getIsDropSql(tableFieldsEntities, isCover);
        // 建表SQL头
        String createSqlHeader = impalaMethodService.getCreateTableHeaderSql(tableFieldsEntities.get(0).getDataBaseName(), tableFieldsEntities.get(0).getTableName());
        // 建表SQL体--字段信息
        String createSqlBody = getCreateSqlBody(tableFieldsEntities, partitionFieldName);
        // 建表SQL--尾括号
        String createSqlFooter = String.format(") \n");
        // 建表SQL--分区字段
        String createSqlPartition = getCreateSqlPartition(tableFieldsEntities, partitionFieldName);
        return isDropSql + createSqlHeader + createSqlBody + createSqlFooter + createSqlPartition;
    }

    private String getCreateSqlPartition(List<TableFieldsEntity> tableFieldsEntities, List<String> partitionFieldName) {
        StringBuilder partitionField = new StringBuilder();
        if (tableFieldsEntities.stream().map(TableFieldsEntity::getPartitioningColumn).collect(Collectors.toList()).contains("Y")) {
            for (TableFieldsEntity tableFields : tableFieldsEntities) {
                if (tableFields.getPartitioningColumn().equals("Y")) {
                    partitionField.append(impalaMethodService.getCreateTablePartitionBodySql(tableFields.getPartitionFieldName(), tableFields.getColumnType()));
                    partitionFieldName = partitionFieldName.stream().filter(e -> !tableFields.getPartitionFieldName().toUpperCase().equals(e)).collect(Collectors.toList());
                }
            }
        }
        partitionFieldName.forEach(fieldName -> {
            partitionField.append(impalaMethodService.getCreateTablePartitionBodySql(fieldName, "STRING"));
        });
        return impalaMethodService.getCreateTablePartitionSql(partitionField.toString().substring(0, partitionField.lastIndexOf(",")).trim());
    }

    private String getCreateSqlBody(List<TableFieldsEntity> tableFieldsEntities, List<String> partitionFieldName) {
        StringBuilder createSqlBody = new StringBuilder();
        for (TableFieldsEntity tableFields : tableFieldsEntities) {
            // 若字段名与分区字段一致，且可以作为分区字段 则不加入到普通字段中
            if (!(partitionFieldName.contains(tableFields.getColumnName().toUpperCase()) && tableFields.getPartitioningColumn().equals("Y"))) {
                createSqlBody.append(impalaMethodService.getCreateTableBodySql(
                        partitionFieldName.contains(tableFields.getColumnName().toUpperCase()) ? tableFields.getColumnName() + "_SRC" : tableFields.getColumnName(),
                        tableFields.getColumnType(),
                        (tableFields.getColumnLength() != null && !tableFields.getColumnLength().equals("0")) ? "(" + tableFields.getColumnLength() + ")" : "",
                        tableFields.getColumnCommet() != null ? impalaMethodService.getCreateTableCommentSql(tableFields.getColumnCommet()) : ""));
            }
        }
        return createSqlBody.toString().substring(0, createSqlBody.lastIndexOf(",")).trim();
    }

    private String getIsDropSql(List<TableFieldsEntity> tableFieldsEntities, String isCover) {
        String isDropSql = "";
        if (isCover.equals("1")) {
            isDropSql = impalaMethodService.getDropTableSql(tableFieldsEntities.get(0).getDataBaseName(), tableFieldsEntities.get(0).getTableName());
        }
        return isDropSql;
    }

    @Override
    public List<Map<String, String>> selectAllFieldType(String sourceCode, String schema, String table) throws SQLException {
        List<TableFieldsEntity> tableFieldsEntities = impalaMethodService.tableStructure(sourceCode, schema, table);
        List<Map<String, String>> result = tableFieldsEntities.stream().map(tableFieldsEntity -> {
            Map<String, String> fieldMap = new HashMap<>();
            fieldMap.put(COLUMN_NAME, tableFieldsEntity.getColumnName().toUpperCase());
            fieldMap.put("data_type", tableFieldsEntity.getColumnType().toUpperCase());
            return fieldMap;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public List<Map<String, String>> selectAllFieldLength(String sourceCode, String schema, String table) throws SQLException {
        List<TableFieldsEntity> tableFieldsEntities = impalaMethodService.tableStructure(sourceCode, schema, table);
        List<Map<String, String>> result = tableFieldsEntities.stream().map(tableFieldsEntity -> {
            Map<String, String> fieldMap = new HashMap<>();
            fieldMap.put(COLUMN_NAME, tableFieldsEntity.getColumnName().toUpperCase());
            fieldMap.put("data_length", StringUtils.isBlank(tableFieldsEntity.getColumnLength()) ? "0" : tableFieldsEntity.getColumnLength());
            return fieldMap;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public List<Map<String, String>> selectFieldAccuracy(String sourceCode, String schema, String table) throws SQLException {
        List<TableFieldsEntity> tableFieldsEntities = impalaMethodService.tableStructure(sourceCode, schema, table);
        List<Map<String, String>> result = tableFieldsEntities.stream().map(tableFieldsEntity -> {
            Map<String, String> fieldMap = new HashMap<>();
            fieldMap.put(COLUMN_NAME, tableFieldsEntity.getColumnName().toUpperCase());
            if (StringUtils.isBlank(tableFieldsEntity.getColumnLength()) || "0.".equals(tableFieldsEntity.getColumnLength())) {
                fieldMap.put("column_accuracy", StringUtils.isBlank(tableFieldsEntity.getColumnLength()) ? "0" : tableFieldsEntity.getColumnLength());
            } else {
                String[] split = tableFieldsEntity.getColumnLength().split(",");
                fieldMap.put("column_accuracy", split.length == 1 ? split[0] : split[1]);
            }
            return fieldMap;
        }).collect(Collectors.toList());
        return result;
    }


    @Override
    protected String selectDataNumSql(String schema, String table, String whereSql) {
        return impalaMethodService.getTableDataNumSql(schema, table, whereSql);
    }


    @Override
    protected String selectCountSumIsNullSql(String schema, String table, String field, String whereSql) {
        if (whereSql != null && whereSql.trim().toUpperCase().startsWith("WHERE")) {
            whereSql = "AND " + whereSql.trim().substring(5);
        }
        return impalaMethodService.getTableIsNullCountSql(schema, table, field, whereSql);
    }
}
